package com.github.limit.handler;


import com.github.limit.annotation.MethodAccessLimit;
import com.github.limit.entity.CurrentLimit;
import com.github.limit.entity.LimitData;
import com.github.limit.entity.MethodCurrentLimit;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: wangdejun
 * @create: 2019-10-11 17:16
 **/
public class MethodAccessLimitHandler extends AbstractLimitHandler<MethodAccessLimit> {

    private final static String name = "methodAccessLimit";


    /**
     * 实际的限流处理逻辑
     *
     * @param methodAccessLimit
     * @param methodName
     * @return
     */
    @Override
    public boolean doHandler(MethodAccessLimit methodAccessLimit, String className, String methodName) {
        // 特殊校验逻辑
        String[] accessKey = getAccessKey(methodAccessLimit, className, methodName);
        iAccessLimit.increase(accessKey[0], accessKey[1]);
        return true;
    }

    /**
     * 限流处理类型的key
     *
     * @return
     */
    @Override
    public Class<? extends Annotation> getType() {
        return MethodAccessLimit.class;
    }

    /**
     * limit:deny:methodAccessLimit:{timeStr}:{className}:{methodName}
     * @param methodAccessLimit
     * @param className
     * @param methodName
     * @return
     */
    @Override
    public String accessKey(MethodAccessLimit methodAccessLimit, String className, String methodName) {
        return className + ":" + methodName;
    }

    /**
     * limit:deny:methodAccessLimit:{timeStr}:{className}:{methodName}
     * @param methodAccessLimit
     * @param className
     * @param methodName
     * @return
     */
    @Override
    public String denyKey(MethodAccessLimit methodAccessLimit, String className, String methodName) {
        return className + ":" + methodName;
    }

    /**
     * 获取限流数值
     *
     * @param methodAccessLimit
     * @return
     */
    @Override
    public long getLimit(MethodAccessLimit methodAccessLimit) {
        return methodAccessLimit.limit();
    }

    @Override
    public String getName() {
        return name;
    }


    /**
     * 限流数据
     *
     * @return
     */
    @Override
    public List<? extends CurrentLimit> limitList() {
        List<LimitData> accessLimitData = iAccessLimit.limitDataList(LIMIT_ACCESS_KEY_PREFIX + getName());

        List<LimitData> denyLimitData = iAccessLimit.limitDataList(LIMIT_DENY_KEY_PREFIX + getName());

        List<MethodCurrentLimit> collect = accessLimitData.stream()
                .map(this::cover2CurrentData).collect(Collectors.toList());

        List<MethodCurrentLimit> collect1 = denyLimitData.stream()
                .map(this::cover2CurrentData).collect(Collectors.toList());

        Map<String, Integer> collect2 = collect1.stream().collect(Collectors.toMap(limit -> {
            return limit.getMethodName() + ":" + limit.getTimeStr();
        }, limit -> {
            return limit.getAccessCount();
        }));

        collect.stream().forEach(limit -> {
            String key = limit.getMethodName() + ":" + limit.getTimeStr();
            int denyCount = Optional.ofNullable(collect2.get(key)).map(value -> value).orElse(0);
            limit.setDenyCount(denyCount);
        });
        return collect;
    }

    private MethodCurrentLimit cover2CurrentData(LimitData limitData) {
        String[] params = limitData.getKey().split(":");
        MethodCurrentLimit currentLimit = new MethodCurrentLimit();
        currentLimit.setType(params[2]);
        currentLimit.setTimeStr(params[3]);
        currentLimit.setClassName(params[4]);
        currentLimit.setMethodName(params[5]);
        currentLimit.setAccessCount(limitData.getCount());
        return currentLimit;
    }
}
